/*
 * Copyright 2025 arisgo@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.arisgo.cloud.attendance.clazz.service.impl;

import com.arisgo.cloud.attendance.clazz.entity.StaffClass;
import com.arisgo.cloud.attendance.clazz.entity.Staff;
import com.arisgo.cloud.attendance.clazz.mapper.StaffClassMapper;
import com.arisgo.cloud.attendance.clazz.service.StaffClassService;
import com.arisgo.cloud.attendance.clazz.vo.ClassInfoDetailVo;
import com.arisgo.cloud.attendance.clazz.vo.StaffClassVo;
import com.arisgo.cloud.attendance.clazz.vo.StaffClassDetailVo;
import com.arisgo.cloud.attendance.clazz.vo.StaffVo;
import com.arisgo.cloud.common.Pagination;
import com.arisgo.cloud.common.dynamic.Header;
import com.arisgo.cloud.common.dynamic.Table;
import com.arisgo.cloud.common.utils.DateUtil;
import com.arisgo.cloud.common.utils.StringUtil;
import com.arisgo.cloud.web.mybatis.service.CloudServiceImpl;
import com.arisgo.cloud.web.param.Paging;
import com.arisgo.cloud.web.param.Param;
import com.arisgo.cloud.web.utils.RequestUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Coulson
 * @since 2024-12-31
 */
@Service
@AllArgsConstructor
public class StaffClassServiceImpl extends CloudServiceImpl<StaffClassMapper, StaffClass, StaffClassVo> implements StaffClassService {

    @Override
    public StaffClass getInstanceModel() {
        return new StaffClass();
    }

    @Override
    public StaffClassVo getInstanceVo() {
        return new StaffClassVo();
    }

    @Override
    public Pagination<StaffClassVo> findStaffByClassId(Long classId, Paging paging) {
        paging.addTenantIdParam(RequestUtil.getTenantId());
        paging.addParam(Param.creator(StringUtil.underlineToCamel(StaffClass.CLASS_ID), classId));
        Map<String, Object> params = paging.convertMap();

        PageHelper.startPage(paging.getPageNo(), paging.getPageSize());
        PageInfo<StaffClassVo> page = new PageInfo<>(this.mapper.findStaffByClassId(params));
        return Pagination.creator(page.getPageNum(), page.getPageSize(), page.getTotal(), page.getList());
    }

    @Override
    public Table<Pagination<?>> pageStaffClass(Long tenantId, LocalDate start, LocalDate end, Paging paging) {
        // 时间只要有一个为空，则取默认值
        if (start == null || end == null) {
            start = DateUtil.weekFirstDay(LocalDate.now());
            end = DateUtil.weekLastDay(LocalDate.now());
        }
        Table<Pagination<?>> table = new Table<>();
        // 设置表头
        List<Header> headers = Lists.newArrayList();
        headers.add(new Header("姓名", Staff.NAME, true));
        headers.add(new Header("工号", Staff.CODE, true));
        LocalDate head = start;
        while (!head.isAfter(end)) {
            Header header = new Header();
            header.setLabel(DateUtil.formatWeek(head) + "(" + head.getMonthValue() + "." + head.getDayOfMonth() + ")");
            header.setField(DateUtil.format(head));
            headers.add(header);
            head = head.plusDays(1);
        }
        table.setHeaders(headers);

        // 分页查询全部人员数据
        paging.addTenantIdParam(tenantId);
        Map<String, Object> params = paging.convertMap();
        Long total = this.mapper.pageStaffClassCount(params);
        List<StaffVo> staffs = this.mapper.pageStaffClass(params);

        if (CollectionUtils.isEmpty(staffs)) {
            table.setData(Pagination.creator(paging.getPageNo(), paging.getPageSize(), total, Lists.newArrayList()));
            return table;
        }
        // 查询班次信息
        List<Long> staffIds = staffs.stream().map(StaffVo::getId).toList();
        List<StaffClassDetailVo> classInfos = Optional.ofNullable(this.mapper.findStaffClassDetail(tenantId, start, end, staffIds)).orElse(Lists.newArrayList());
        Map<String, List<StaffClassDetailVo>> classDetailMap = classInfos.stream().collect(Collectors.groupingBy(StaffClassDetailVo::getStaffCode));

        Map<String, Map<String, Object>> data = Maps.newHashMapWithExpectedSize(staffs.size());
        for (StaffVo staff : staffs) {
            String staffCode = staff.getCode();
            Map<String, Object> row = data.get(staffCode);
            if (CollectionUtils.isEmpty(row)) {
                row = Maps.newHashMapWithExpectedSize(headers.size());
                row.put(Staff.ID, staff.getId());
                row.put(Staff.CODE, staffCode);
                row.put(Staff.NAME, staff.getName());
                data.put(staffCode, row);
            }
            List<StaffClassDetailVo> details = classDetailMap.get(staffCode);
            if (!CollectionUtils.isEmpty(details)) {
                for (StaffClassDetailVo detail : details) {
                    String dateKey = DateUtil.format(detail.getWorkDate());
                    row.merge(dateKey, detail.getShiftName(), (a, b) -> a + ", " + b);
                }
            }

        }
        table.setData(Pagination.creator(paging.getPageNo(), paging.getPageSize(), total, data.values().stream().toList()));
        return table;
    }

    @Override
    public Table<Pagination<?>> pageStaffWeek(Long tenantId, LocalDate date, Paging paging) {
        if (null == date) {
            date = LocalDate.now();
        }
        LocalDate start = DateUtil.weekFirstDay(date);
        LocalDate end = DateUtil.weekLastDay(date);
        return pageStaffClass(tenantId, start, end, paging);
    }

    @Override
    public List<ClassInfoDetailVo> findClassDetailByStaff(Long staffId, LocalDate date) {
        Long tenantId = RequestUtil.getTenantId();
        return this.mapper.findClassByStaff(tenantId, staffId, date);
    }
}
